#include "csr.h"
#include "mmu.h"
#include "print.h"

// M模式扩展状态寄存器定义
#define MXSTATUS_PMDU          (1 << 10)  /* U模式下禁止性能计数器计数 */
#define MXSTATUS_PMDS          (1 << 11)  /* S模式下禁止性能计数器计数 */
#define MXSTATUS_PMDM          (1 << 13)  /* M模式下禁止性能计数器计数 */
#define MXSTATUS_PMP4K         (1 << 14)  /* reserve */
#define MXSTATUS_MM            (1 << 15)  /* 支持非对齐访问 */
#define MXSTATUS_UCME          (1 << 16)  /* U模式可以执行cache操作指令 */
#define MXSTATUS_CLINTEE       (1 << 17)  /* 使能S模式响应软中断和定时器中断 */
#define MXSTATUS_MHRD          (1 << 18)  /* 关闭TLB MISS后硬件自动回填 */
#define MXSTATUS_MAEE          (1 << 21)  /* 使能MMU pte扩展属性位 */
#define MXSTATUS_THEADISAEE    (1 << 21)  /* 使能C906扩展指令 */

// M模式硬件配置寄存器定义
#define MHCR_IE			       (1 << 0)	  /* icache enable */
#define MHCR_DE			       (1 << 1)	  /* dcache enable */
#define MHCR_WA			       (1 << 2)	  /* dcache write allocate */
#define MHCR_WB			       (1 << 3)	  /* dcache write back */
#define MHCR_RS			       (1 << 4)	  /* return stack enable */
#define MHCR_BPE		       (1 << 5)   /* branch prediction enable */
#define MHCR_BTB		       (1 << 6)	  /* branch target prediction enable */
#define MHCR_WBR		       (1 << 8)	  /* write burst enable */

// M模式硬件操作寄存器定义
#define MCOR_CACHE_SEL_ICACHE	(0x1 << 0)  /* 选中icache */
#define MCOR_CACHE_SEL_DCACHE	(0x2 << 0)  /* 选中dcache */
#define MCOR_CACHE_SEL_BOTH	    (0x3 << 0)  /* 选中icache和dcache */
#define MCOR_INV		        (1 << 4)    /* cache正在无效化操作 */
#define MCOR_CLR		        (1 << 5)    /* 脏cache会被写到片外 */
#define MCOR_BHT_INV		    (1 << 16)   /* 分支历史表数据进行无效化 */
#define MCOR_BTB_INV		    (1 << 17)   /* 分支目标缓冲器数据进行无效化 */

// M模式隐士操作寄存器定义
#define MHINT_DPLD		        (1 << 2)	/* 使能dcache预取 */
#define MHINT_AMR_PAGE		    (0x0 << 3)  /* 写分配策略由访问地址的页面属性WA决定 */
#define MHINT_AMR_LIMIT_3	    (0x1 << 3)  /* 阈值3条cacheline */
#define MHINT_AMR_LIMIT_64	    (0x2 << 3)  /* 阈值64条cacheline */
#define MHINT_AMR_LIMIT_128	    (0x3 << 3)  /* 阈值128条cacheline */
#define MHINT_IPLD		        (1 << 8)	/* 使能icache预取 */
#define MHINT_IWPE		        (1 << 9)	/* 使能icache路预测 */
#define MHINT_DIS_PREFETCH_2	(0x0 << 13) /* dcache预取2条cacheline */
#define MHINT_DIS_PREFETCH_4	(0x1 << 13) /* dcache预取4条cacheline */
#define MHINT_DIS_PREFETCH_8	(0x2 << 13) /* dcache预取8条cacheline */
#define MHINT_DIS_PREFETCH_16	(0x3 << 13) /* dcache预取16条cacheline */

// 同步指令并清空指令流水线
#define sync_i()		asm volatile (".long 0x01a0000b" ::: "memory")

// 回写并失效所有dcache
void os_clean_dcache_all(void)
{
	asm volatile (".long 0x0030000b" ::: "memory"); /* dcache.ciall */
	sync_i();
}

// 回写并失效指定物理地址对应dcache
void os_clean_dcache_range_pa(unsigned long start, unsigned long end)
{
	register unsigned long i asm("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;

	for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
		asm volatile (".long 0x02b5000b" ::: "memory"); /* dcache.cipa a0 */
	sync_i();
}

// 回写并失效指定虚拟地址对应dcache
void os_clean_dcache_range(unsigned long start, unsigned long end)
{
	register unsigned long i asm("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;

	for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
		asm volatile (".long 0x0275000b" ::: "memory"); /* dcache.civa a0 */
	sync_i();
}

// 失效所有dcache
void os_invalidate_dcache_all(void)
{
	asm volatile (".long 0x0020000b" ::: "memory"); /* dcache.iall */
	sync_i();
}

// 失效指定物理地址对应dcache
void os_invalidate_dcache_range_pa(unsigned long start, unsigned long end)
{
	register unsigned long i asm("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;

	for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
		asm volatile (".long 0x02a5000b" ::: "memory"); /* dcache.ipa a0 */
	sync_i();
}

// 失效指定虚拟地址对应dcache
void os_invalidate_dcache_range(unsigned long start, unsigned long end)
{
	register unsigned long i asm("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;

	for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
		asm volatile (".long 0x0265000b" ::: "memory"); /* dcache.iva a0 */
	sync_i();
}

// 回写所有dcache
void os_flush_dcache_all(void)
{
	asm volatile (".long 0x0010000b" ::: "memory"); /* dcache.call */
	sync_i();
}

// 回写指定物理地址对应dcache
void os_flush_dcache_range_pa(unsigned long start, unsigned long end)
{
	register unsigned long i asm("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;

	for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
		asm volatile (".long 0x0285000b" ::: "memory"); /* dcache.cpa a0 */
	sync_i();
}

// 回写指定虚拟地址对应dcache
void os_flush_dcache_range(unsigned long start, unsigned long end)
{
	register unsigned long i asm("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;

	for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
		asm volatile (".long 0x0245000b" ::: "memory"); /* dcache.cva a0 */
	sync_i();
}

// 失效所有icache
void os_invalidate_icache_all(void)
{
	asm volatile (".long 0x0100000b" ::: "memory"); /* icache.iall */
	sync_i();
}

// 失效指定物理地址对应icache
void os_invalidate_icache_range_pa(unsigned long start, unsigned long end)
{
	register unsigned long i asm("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;

	for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
		asm volatile (".long 0x0385000b" ::: "memory"); /* icache.ipa a0 */
	sync_i();
}

// 失效指定虚拟地址对应icache
void os_invalidate_icache_range(unsigned long start, unsigned long end)
{
	register unsigned long i asm("a0") = start & -CONFIG_SYS_CACHELINE_SIZE;

	for (; i < end; i += CONFIG_SYS_CACHELINE_SIZE)
		asm volatile (".long 0x0305000b" ::: "memory"); /* icache.iva a0 */
	sync_i();
}

// 使能icache
void os_icache_enable(void)
{
	os_invalidate_icache_all();
	csr_set(mhcr, MHCR_IE | MHCR_RS | MHCR_BPE | MHCR_BTB);
	csr_set(mhint, MHINT_IPLD | MHINT_IWPE);
}

// 关闭icache
void os_icache_disable(void)
{
	csr_clear(mhcr, MHCR_IE);
}

// 获取icache状态
int os_icache_status(void)
{
	return csr_read(mhcr) & MHCR_IE;
}

// 使能dcache
void os_dcache_enable(void)
{
	os_invalidate_dcache_all();
	csr_set(mhcr, MHCR_DE | MHCR_WA | MHCR_WB | MHCR_WBR);
	csr_set(mhint, MHINT_DPLD | MHINT_AMR_LIMIT_3);
}

// 关闭dcache
void os_dcache_disable(void)
{
	os_flush_dcache_all();
	csr_clear(mhcr, MHCR_DE);
}

// 获取dcache状态
int os_dcache_status(void)
{
	return csr_read(mhcr) & MHCR_DE;
}

void rv_cpu_init(void)
{
    csr_set(mxstatus, MXSTATUS_MM | MXSTATUS_UCME | MXSTATUS_CLINTEE | MXSTATUS_MAEE | MXSTATUS_THEADISAEE);
}

void cache_test(void)
{
    volatile int i, j;

    for (i = 0; i < (1000 * 10000); i++) {
        j++;
		if (!(i % (100 * 10000))) {
   	        printk("#");
		}
    }
   	printk("\n");
}
